#pragma once

// likely/unlikely
#ifdef _POSIX_VERSION
#define MQ_LIKELY(x) (__builtin_expect(!!(x), 1))
#define MQ_UNLIKELY(x) (__builtin_expect(!!(x), 0))
#else
#define MQ_LIKELY(x) (x)
#define MQ_UNLIKELY(x) (x)
#endif

// disallow copy
#define MQ_DISALLOW_COPY_AND_ASSIGN(classname) \
    classname(const classname &) = delete;     \
    classname &operator=(const classname &) = delete; // NOLINT

// singleton check
#define MQ_SINGLETON_CHECK(classname)                                                                   \
private:                                                                                                \
    struct ConstructorChecker                                                                           \
    {                                                                                                   \
        inline ConstructorChecker()                                                                     \
        {                                                                                               \
            static_assert(std::is_final_v<classname>, "Constructor must be final.");                    \
            static_assert(!std::is_default_constructible_v<classname>, "Constructor must be private."); \
            static std::atomic_flag flag;                                                               \
            if MQ_UNLIKELY (flag.test_and_set())                                                        \
            {                                                                                           \
                throw std::runtime_error("Constructor has been instantiated.");                         \
            }                                                                                           \
        }                                                                                               \
    };                                                                                                  \
                                                                                                        \
    ConstructorChecker constructor_checker_;

// singleton declare
#define MQ_SINGLETON_DECLARE(classname)           \
public:                                           \
    inline static classname &get()                \
    { /*NOLINT*/                                  \
        static classname singleton = classname(); \
        return singleton;                         \
    }                                             \
                                                  \
private:                                          \
    MQ_SINGLETON_CHECK(classname)                 \
    MQ_DISALLOW_COPY_AND_ASSIGN(classname)
